package main

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
)

var (
	clientCert0 = "./gen_crypto/crypto-config/peerOrganizations/org1.demo.com/peers/peer0.org1.demo.com/tls/server.crt" // client's cert
	clientKey0  = "./gen_crypto/crypto-config/peerOrganizations/org1.demo.com/peers/peer0.org1.demo.com/tls/server.key" // client's private key
	clientCert1 = "./gen_crypto/crypto-config/peerOrganizations/org2.demo.com/peers/peer0.org2.demo.com/tls/server.crt" // client's cert
	clientKey1  = "./gen_crypto/crypto-config/peerOrganizations/org2.demo.com/peers/peer0.org2.demo.com/tls/server.key" // client's private key
	clientCert2 = "./gen_crypto/crypto-config/peerOrganizations/org3.demo.com/peers/peer0.org3.demo.com/tls/server.crt" // client's cert
	clientKey2  = "./gen_crypto/crypto-config/peerOrganizations/org3.demo.com/peers/peer0.org3.demo.com/tls/server.key" // client's private key
	clientCert3 = "./gen_crypto/crypto-config/peerOrganizations/org4.demo.com/peers/peer0.org4.demo.com/tls/server.crt" // client's cert
	clientKey3  = "./gen_crypto/crypto-config/peerOrganizations/org4.demo.com/peers/peer0.org4.demo.com/tls/server.key" // client's private key
)

//以TLS的形式从其他机构获得对象的默克证明
func GetMerkleRootFromTLS(obj Transaction, offset int, client *http.Client) ([]byte, error) {
	// IP := "10.10.9.20"
	IP := ClusterName(int(obj.From)) + strconv.Itoa(obj.BlockId) + "&type=merkleproof" + "&oid="
	data := make([]byte, 4096)
	data, err := ReadFromClustersTLS(IP, string(obj.Hash), client)
	if err != nil {
		log.Println("cluster", Cluster, ":", "抽查失败", string(obj.Hash), ": http error")
		return data, err
	} else {
		log.Println("cluster", Cluster, ":", "抽查成功", string(obj.Hash))
		return data, nil
	}
}

//以TLS的形式从其他机构获得对象的默克证明
func ReadFromClustersTLS(IP string, obj string, client *http.Client) ([]byte, error) {
	url := IP + obj
	log.Println("cluster", Cluster, ":", url)
	resp, err := client.Get(url)
	if err != nil {
		fmt.Println("Get error:", err)
		return nil, err
	}
	defer resp.Body.Close()
	ret, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	log.Println("cluster", Cluster, ":", "接收证明", obj, len(ret))
	return ret, nil
}

//以TLS的形式从其他机构获得恢复数据
func GetBlockFromTLS(obj string, from int, client *http.Client) ([]byte, error) {
	// IP := "10.10.9.20"
	IP := ClusterName(from) + "0" + "&type=repair" + "&oid="
	data := make([]byte, 4096*1024)
	data, err := ReadBlockFromClustersTLS(IP, obj, client)
	if err != nil {
		log.Println("cluster", Cluster, ":", "获取失败", obj, ": http error")
		return data, err
	} else {
		log.Println("cluster", Cluster, ":", "获取成功", obj)
		return data, nil
	}
}

//以TLS的形式从其他机构获得恢复数据
func ReadBlockFromClustersTLS(IP string, obj string, client *http.Client) ([]byte, error) {
	url := IP + obj
	log.Println("cluster", Cluster, ":", url)
	resp, err := client.Get(url)
	if err != nil {
		fmt.Println("Get error:", err)
		return nil, err
	}
	defer resp.Body.Close()
	ret, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if len(ret) == 0 {
		log.Println("cluster", Cluster, ":", "接收数据为空", obj)
		return ret, errors.New("nil")
	}
	log.Println("cluster", Cluster, ":", "接收数据", obj, len(ret))
	return ret, nil
}

func ClusterName(cluster int) (IP string) {
	switch cluster {
	case 0:
		IP = "https://peer0.org1.demo.com:1000" + strconv.Itoa(Cluster) + "/get?off="
	case 1:
		IP = "https://peer0.org2.demo.com:1000" + strconv.Itoa(Cluster) + "/get?off="
	case 2:
		IP = "https://peer0.org3.demo.com:1000" + strconv.Itoa(Cluster) + "/get?off="
	case 3:
		IP = "https://peer0.org4.demo.com:1000" + strconv.Itoa(Cluster) + "/get?off="
	default:
		log.Println("cluster", Cluster, ":", "error when read obj: Cluster Number Error")
		return
	}
	return IP
}

func tls_client() (client *http.Client) {
	pool := x509.NewCertPool()

	addTrust(pool, caCert0)
	addTrust(pool, caCert1)
	addTrust(pool, caCert2)
	addTrust(pool, caCert3)

	// addTrust(pool, caCert)

	clientCert, clientKey := ClusterClient()

	cliCrt, err := tls.LoadX509KeyPair(clientCert, clientKey)
	if err != nil {
		fmt.Println("Loadx509keypair err:", err)
		return
	}

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			RootCAs:      pool,
			Certificates: []tls.Certificate{cliCrt},
			// InsecureSkipVerify: true,
		},
	}
	client = &http.Client{Transport: tr}

	// resp, err := client.Get("https://peer0.org2.demo.com:12306/get?oid=123")
	// //resp, err := client.Get("https://10.10.9.49:12306")
	// if err != nil {
	// 	fmt.Println("Get error:", err)
	// 	return
	// }
	// defer resp.Body.Close()
	// body, err := ioutil.ReadAll(resp.Body)
	// fmt.Println(string(body))
	return client
}

func addTrust(pool *x509.CertPool, path string) {
	aCrt, err := ioutil.ReadFile(path)
	if err != nil {
		fmt.Println("ReadFile err:", err)
		return
	}
	pool.AppendCertsFromPEM(aCrt)
}

func ClusterClient() (certFile string, keyFile string) {
	if Cluster == 0 {
		certFile = clientCert0
		keyFile = clientKey0
		return certFile, keyFile
	}
	if Cluster == 1 {
		certFile = clientCert1
		keyFile = clientKey1
		return certFile, keyFile
	}
	if Cluster == 2 {
		certFile = clientCert2
		keyFile = clientKey2
		return certFile, keyFile
	}
	if Cluster == 3 {
		certFile = clientCert3
		keyFile = clientKey3
		return certFile, keyFile
	}
	return
}
